use super::{event_list_new, timer_rbtree_new, BoxedPoll, Event, Poll, Timer, Waker, POLLIN};
use crate::{time, Error};
use core::ptr;
use core::time::Duration;
use hicollections::{List, RbTree};
use hioff::container_of_mut;
use hipool::{Boxed, MemPool, NullAlloc};

type Pool = &'static MemPool;

struct StopEvent {
    waker: Waker,
    event: Event,
    stopped: bool,
}

#[repr(C)]
pub struct Scheduler {
    poll: BoxedPoll,
    events: List<Event>,
    monitors: List<Event>,
    timers: RbTree<Timer>,
    private_data: *const (),
    now: Duration,
    stop: StopEvent,
}

pub type BoxedScheduler = Boxed<'static, Scheduler, NullAlloc>;

impl Scheduler {
    pub fn new_in(pool: Pool) -> Result<BoxedScheduler, Error> {
        let waker = Waker::new()?;
        let poll = Poll::new_in(pool)?;
        let mut boxed = Boxed::new_in(
            pool,
            Self {
                stop: StopEvent {
                    event: Event::new(Self::stop_event_handle),
                    waker,
                    stopped: false,
                },
                poll,
                events: event_list_new(),
                monitors: event_list_new(),
                timers: timer_rbtree_new(),
                now: time::now(),
                private_data: ptr::null(),
            },
        )?;
        boxed.active_stop_event();
        Ok(boxed.into())
    }
}

impl Scheduler {
    fn active_stop_event(&mut self) {
        let _ = self
            .poll
            .add_event(self.stop.waker.fd, POLLIN, &self.stop.event);
    }

    fn stop_event_handle(event: &Event, _events: u32, _sched: &mut Scheduler) {
        let this = unsafe { container_of_mut!(event, Self, stop.event) };
        if this.stop.waker.awaken() {
            this.stop.stopped = true;
        }
    }

    fn wait_timeout(&self) -> i32 {
        if !self.events.empty() {
            0
        } else if let Some(first) = self.timers.first() {
            let timeout = first.timeout.get();
            if timeout <= self.now {
                0
            } else {
                (timeout - self.now).as_millis() as i32
            }
        } else {
            -1
        }
    }

    fn dispatch_monitors(&mut self) {
        if !self.monitors.empty() {
            let mut list = event_list_new();
            self.monitors.move_head(&mut list);
            for event in list.iter() {
                event.handle(0, self);
            }
            list.move_head(&mut self.monitors);
        }
    }

    fn dispatch_events(&mut self) {
        let mut list = event_list_new();
        self.events.move_head(&mut list);
        while let Some(first) = list.first() {
            unsafe { list.del(first) };
            first.handle(first.events.get(), self);
        }
    }

    fn dispatch_fd_events(&mut self, list: &mut List<Event>) {
        while let Some(first) = list.first() {
            unsafe { list.del(first) };
            first.handle(first.events.get(), self);
        }
    }

    fn dispatch_timers(&mut self) {
        while let Some(first) = self.timers.first() {
            if first.timeout.get() <= self.now {
                self.timers.remove(first);
                first.handle(self);
            } else {
                break;
            }
        }
    }
}

impl Scheduler {
    pub fn run(&mut self) {
        let mut list = List::<Event>::new(|e| unsafe { ptr::addr_of!((*e).node) });
        while !self.stop.stopped {
            self.now = time::now();
            let timeout = self.wait_timeout();
            let Ok(_) = self.poll.wait(timeout, |events, event| {
                let event = unsafe { &*(event) };
                event.events.set(events);
                unsafe { list.add_tail(event) };
            }) else { continue };
            if timeout > 0 {
                self.now = time::now();
            }
            self.dispatch_timers();
            self.dispatch_fd_events(&mut list);
            self.dispatch_events();
            self.dispatch_monitors();
        }
    }

    pub fn stop(&self) {
        self.stop.waker.wake();
    }

    pub fn stopped(&self) -> bool {
        self.stop.stopped
    }

    pub fn now(&self) -> Duration {
        self.now
    }

    /// # Safety
    /// 调用之后e不能转移所有权
    pub unsafe fn add_monitor(&mut self, e: &Event) {
        self.monitors.del(e);
        self.monitors.add_tail(e);
    }

    /// # Safety
    /// 调用之后e不能转移所有权
    pub unsafe fn add_event(&mut self, e: &Event, events: u32, _priority: i32) {
        self.del_event(e);
        self.events.add_tail(e);
        e.events.set(events);
    }

    /// # Safety
    /// 调用之后所有event不能转移所有权
    pub unsafe fn add_event_list(&mut self, events: &mut List<Event>, _priority: i32) {
        events.move_tail(&mut self.events);
    }

    /// # Safety
    /// e应该调用了add_event
    pub unsafe fn del_event(&mut self, e: &Event) {
        self.events.del(e);
    }

    /// # Safety
    /// 调用之后e不能转移所有权
    pub unsafe fn add_fd_event(&self, e: &Event, events: u32, fd: i32) -> Result<(), Error> {
        self.poll.add_event(fd, events, e as *const Event)
    }

    /// # Safety
    /// e应该调用了add_fd_event
    pub unsafe fn mod_fd_event(&self, e: &Event, events: u32, fd: i32) -> Result<(), Error> {
        self.poll.mod_event(fd, events, e as *const Event)
    }

    /// # Safety
    /// e应该调用了add_fd_event
    pub unsafe fn del_fd_event(&self, fd: i32) -> Result<(), Error> {
        self.poll.del_event(fd)
    }

    /// # Safety
    /// 调用之后t不能转移所有权
    pub unsafe fn set_timer(&mut self, t: &Timer, micros: u32) {
        self.timers.remove(t);
        t.timeout
            .set(self.now + Duration::from_micros(micros as u64));
        self.timers.insert(t, false);
    }

    /// # Safety
    /// t应该调用set_timer了
    pub unsafe fn del_timer(&mut self, t: &Timer) {
        self.timers.remove(t);
    }

    pub fn private_data(&self) -> *const () {
        self.private_data
    }

    pub fn set_private_data(&mut self, data: *const ()) {
        self.private_data = data;
    }
}
